package io.shuttle.mbe.api

import io.shuttle.mbe.api.annotation.PromiseStyleMinVersion
import io.shuttle.mbe.api.annotation.ChromeMinVersion
import io.shuttle.mbe.api.types.Value1Function
import io.shuttle.mbe.api.types.Value2Function
import io.shuttle.mbe.api.types.VoidFunction
import io.shuttle.mbe.core.Promise

////////////////////
// Printing
////////////////////
/**
 * Use the `Browser.printing` API to send print jobs to printers installed on Chromebook.

 * Permissions: "printing"
 * @platform ChromeOS only
 * @since Chrome 81
 */
interface Printing {
    // The maximum number of times that getPrinterInfo can be called per minute. default is 20
    val MAX_GET_PRINTER_INFO_CALLS_PER_MINUTE: Int

    // The maximum number of times that submitJob can be called per minute. default is 20
    val MAX_SUBMIT_JOB_CALLS_PER_MINUTE: Int

    // Cancels previously submitted job.
    @PromiseStyleMinVersion(100)
    abstract fun cancelJob(
        // The id of the print job to cancel. This should be the same id received in a SubmitJobResponse.
        jobId: String,
        callback: VoidFunction? = null
    ): Promise<Void>

    // Returns the status of the print job.
    // This call will fail with a runtime error if the print job with the given jobId doesn't exist.
    // jobId: The id of the print job to return the status of.
    // This should be the same id received in a SubmitJobResponse.
    @PromiseStyleMinVersion(100)
    @ChromeMinVersion(135)
    abstract fun getJobStatus(
        jobId: String,
        callback: Value1Function<JobStatus>
    ): Promise<JobStatus>

    // Returns the status and capabilities of the printer in CDD format.
    // This call will fail with a runtime error if no printers with given id are installed.
    @PromiseStyleMinVersion(100)
    abstract fun getPrinterInfo(
        printerId: String,
        callback: Value1Function<GetPrinterInfoResponse>
    ): Promise<GetPrinterInfoResponse>

    // Returns the list of available printers on the device.
    // This includes manually added, enterprise and discovered printers.
    @PromiseStyleMinVersion(100)
    abstract fun getPrinters(
        callback: Value1Function<List<Printer>>
    ): Promise<List<Printer>>

    // Submits the job for printing.
    // If the extension is not listed in the PrintingAPIExtensionsAllowlist policy,
    // the user is prompted to accept the print job. Before Chrome 120, this function did not return a promise.
    @PromiseStyleMinVersion(100)
    abstract fun submitJob(
        request: SubmitJobRequest,
        callback: Value1Function<SubmitJobResponse>
    ): Promise<SubmitJobResponse>

    // Event fired when the status of the job is changed. This is only fired for the jobs created by this extension.
    // @callback jobId: String
    // @callback status: JobStatus
    abstract val onJobStatusChanged: Events.Event<Value2Function<String, JobStatus>>?

    data class GetPrinterInfoResponse(
        // Printer capabilities in CDD format. The property may be missing.
        var capabilities: Any,
        // The status of the printer.
        var status: PrinterStatus,
    )

    enum class JobStatus {
        // Print job is received on Chrome side but was not processed yet.
        PENDING,

        // Print job is sent for printing.
        IN_PROGRESS,

        // Print job was interrupted due to some error.
        FAILED,

        // Print job was canceled by the user or via API.
        CANCELED,

        // Print job was printed without any errors.
        PRINTED,
    }

    data class Printer(
        // The human-readable description of the printer.
        var description: String,
        // The printer's identifier; guaranteed to be unique among printers on the device.
        var id: String,
        // The flag which shows whether the printer fits DefaultPrinterSelection rules.
        // Note that several printers could be flagged.
        var isDefault: Boolean,
        // The name of the printer.
        var name: String,
        // The value showing how recent the printer was used for printing from Chrome.
        // The lower the value is the more recent the printer was used.
        // The minimum value is 0. Missing value indicates that the printer wasn't used recently.
        // This value is guaranteed to be unique amongst printers.
        var recentlyUsedRank: Number?,
        // The source of the printer (user or policy configured).
        var source: PrinterSource,
        // The printer URI. This can be used by extensions to choose the printer for the user.
        var uri: String,
    )

    enum class PrinterSource {
        // Printer was added by user.
        USER,

        // Printer was added via policy.
        POLICY,
    }

    enum class PrinterStatus {
        // The door of the printer is open. Printer still accepts print jobs.
        DOOR_OPEN,

        // The tray of the printer is missing. Printer still accepts print jobs.
        TRAY_MISSING,

        // The printer is out of ink. Printer still accepts print jobs.
        OUT_OF_INK,

        // The printer is out of paper. Printer still accepts print jobs.
        OUT_OF_PAPER,

        // The output area of the printer (e.g. tray) is full. Printer still accepts print jobs.
        OUTPUT_FULL,

        // The printer has a paper jam. Printer still accepts print jobs.
        PAPER_JAM,

        // Some generic issue. Printer still accepts print jobs.
        GENERIC_ISSUE,

        // The printer is stopped and doesn't print but still accepts print jobs.
        STOPPED,

        // The printer is unreachable and doesn't accept print jobs.
        UNREACHABLE,

        // The SSL certificate is expired. Printer accepts jobs but they fail.
        EXPIRED_CERTIFICATE,

        // The printer is available.
        AVAILABLE
    }

    data class SubmitJobRequest(
        // The print job to be submitted. Supported content types are "application/pdf" and "image/png".
        // The Cloud Job Ticket shouldn't include FitToPageTicketItem,
        // PageRangeTicketItem and ReverseOrderTicketItem fields since they are irrelevant for native printing.
        // VendorTicketItem is optional. All other fields must be present.
        var job: PrinterProvider.PrintJob,
    )

    data class SubmitJobResponse(
        // The id of created print job.
        // This is a unique identifier among all print jobs on the device.
        // If status is not OK, jobId will be null.
        var jobId: String?,
        // The status of the request.
        var status: SubmitJobStatus
    )

    enum class SubmitJobStatus {
        // Sent print job request is accepted.
        OK,

        // Sent print job request is rejected by the user.
        USER_REJECTED
    }
}